#include "Timer.h"

#ifdef WIN32
#include <Windows.h>

extern inline uint64_t __rdtsc();
#else
#include <unistd.h>

inline uint64_t __rdtsc()
{
	__asm
	("							\
		xor %rax, %rax\n\t		\
		xor %rdx, %rdx\n\t		\
		rdtsc\n\t				\
		shl $32, %rdx\n\t		\
		or %rdx, %rax			\
	");
}
#endif

#ifdef WIN32
#define TIME (500)
#define TIME_CALC (TIME)
#define sleep(x) Sleep(x)
#else
#define TIME (1)
#define TIME_CALC (TIME * 1000)
#endif

uint64_t __cpuspeed()
{
	uint64_t cpuspeed;
	uint64_t beg = __rdtsc();

	sleep(TIME);

	uint64_t end = __rdtsc();		
	cpuspeed = (end - beg) / double(TIME_CALC) * 1000;

	return cpuspeed;
}

uint64_t Timer::cpuspeed = __cpuspeed();

Timer::Timer()
	: started(false), ended(false), begin(0), interval(0)
{
}

void Timer::start()
{
	started = true;

	begin = __rdtsc();
}

uint64_t Timer::end()
{
	interval = __rdtsc() - begin;

	started = true;
	ended = true;

	return interval;
}

void Timer::reset()
{
	started = false;
	ended = false;
	begin = 0;
	interval = 0;
}

uint64_t Timer::getNanoseconds()
{
	uint64_t i;

	if (!getInterval(i))
	{
		return -1;
	}	

	return i / float(cpuspeed / 1000000000.);
}

uint64_t Timer::getMicroseconds()
{
	uint64_t i;

	if (!getInterval(i))
	{
		return -1;
	}	

	return i / float(cpuspeed / 1000000.);
}

uint64_t Timer::getMilliseconds()
{
	uint64_t i;

	if (!getInterval(i))
	{
		return -1;
	}	

	return i / float(cpuspeed / 1000.);
}

uint64_t Timer::getSeconds()
{
	uint64_t i;

	if (!getInterval(i))
	{
		return -1;
	}	

	return i / float(cpuspeed);
}

uint64_t Timer::getMinutes()
{
	uint64_t i;

	if (!getInterval(i))
	{
		return -1;
	}	

	return (i / float(cpuspeed)) / 60.;
}

bool Timer::getInterval(uint64_t &t)
{
	if (!started)
	{
		return false;
	}

	uint64_t i;
	if (!ended)
	{
		i = __rdtsc() - begin;
	}
	else
	{
		i = interval;
	}

	t = i;

	return true;
}